package com.se.global;

import cn.hutool.core.util.StrUtil;
import com.se.domain.vo.ResultVO;
import com.se.enums.ResultCode;
import com.se.exception.ResultException;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingRequestValueException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.support.MissingServletRequestPartException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@RestControllerAdvice
public class ExceptionAdviceHandler {
	@ExceptionHandler({MissingRequestValueException.class, MissingServletRequestPartException.class})
	public ResultVO<Object> RestParamExceptionHandler(Exception e){
		return ResultVO.fail(ResultCode.PARAM_INVALID.getCode(), e.getMessage());
	}
	@ExceptionHandler(ResultException.class)
	public ResultVO<Object> resultExceptionHandler(ResultException e){
		log.warn(e.getMessage(), e);
		return ResultVO.fail(e.getCode(), e.getMsg());
	}

	@ExceptionHandler(ConstraintViolationException.class)
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	public ResultVO<Object> constraintViolationException(ConstraintViolationException ex) {
		log.warn("ConstraintViolationException:", ex);
		Set<ConstraintViolation<?>> violations = ex.getConstraintViolations();
		String msg = violations.stream().map(ConstraintViolation::getMessage).collect(Collectors.joining(";"));

		return ResultVO.fail(ResultCode.PARAM_INVALID.getCode(), msg);
	}

	@ExceptionHandler(BindException.class)
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	public ResultVO<Object> bindException(BindException ex) {
		log.warn("BindException:", ex);
		try {
			// 拿到@NotNull,@NotBlank和 @NotEmpty等注解上的message值
			String msg = Objects.requireNonNull(ex.getBindingResult().getFieldError()).getDefaultMessage();
			if (StrUtil.isNotEmpty(msg)) {
				// 自定义状态返回
				return ResultVO.fail(ResultCode.PARAM_INVALID.getCode(), msg);
			}
		} catch (Exception ignored) {
		}
		// 参数类型不匹配检验
		StringBuilder msg = new StringBuilder();
		List<FieldError> fieldErrors = ex.getFieldErrors();
		fieldErrors.forEach((oe) ->
				msg.append("参数:[").append(oe.getObjectName())
						.append(".").append(oe.getField())
						.append("]的传入值:[").append(oe.getRejectedValue()).append("]与预期的字段类型不匹配.")
		);
		return ResultVO.fail(ResultCode.PARAM_INVALID.getCode(), msg.toString());
	}

	@ExceptionHandler(MethodArgumentNotValidException.class)
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	public ResultVO<Object> methodArgumentNotValidException(MethodArgumentNotValidException ex) {
		log.warn("MethodArgumentNotValidException:", ex);
		return ResultVO.fail(ResultCode.PARAM_INVALID.getCode(), Objects.requireNonNull(ex.getBindingResult().getFieldError()).getDefaultMessage());
	}
}
